package ru.miit.elearning.hibernate.dao;

import java.util.Calendar;
import java.util.List;
import org.hibernate.Session;
import ru.miit.elearning.hibernate.dto.Account;
import ru.miit.elearning.hibernate.dto.Announcement;
import ru.miit.elearning.hibernate.dto.AnnouncementType;
import ru.miit.elearning.hibernate.dto.CurriculumLevel;

/**
 *
 * @author Cyclone
 */
public class AnnouncementDAO extends GenericDAO {

    public AnnouncementDAO(Session session) {
        super(session);
    }

    public List<Announcement> findAnnouncementsByPage(int min, int count) {
        min = Math.max(min, 0);
        return session.createQuery("from Announcement "
                + "order by creationDate desc").setFirstResult(min).setMaxResults(count).list();
    }

    /**
     * Finds a page of announcements, devoted to a course, learnt by a student or checked by a tutor
     * @param min page start
     * @param count page size
     * @param userId id of a student or a tutor
     * @return list of accouncements
     */
    public List<Announcement> findAnnouncementsByPageByUser(int min, int count, int userId) {
        min = Math.max(min, 0);
        return session.createQuery("from Announcement "
                + "where curriculumLevel is null "
                + "or curriculumLevel in "
                + "(select ud2.curriculumLevel "
                + "from UserData ud2 where "
                + "ud2.id.account = :userId) "
                + "order by creationDate desc").setParameter("userId", userId).setFirstResult(min).setMaxResults(count).list();
    }

    public Announcement findLatestAnnouncement() {
        return findAnnouncementsByPage(0, 1).get(0);
    }

    public Announcement findLatestAnnouncementByUser(int userId) {
        return findAnnouncementsByPageByUser(0, 1, userId).get(0);
    }

    public Announcement addAnnouncement(int userId, int type, String subject, String content, Integer curriculumLevelId) {
        Announcement announcement = new Announcement();

        Account account = (Account) session.get(Account.class, userId);
        announcement.setAccount(account);

        if (curriculumLevelId != null) {
            announcement.setCurriculumLevel((CurriculumLevel) session.get(CurriculumLevel.class, curriculumLevelId));
        }



        announcement.setAnnouncementType(new AnnouncementType(type));
        announcement.setSubject(subject);
        announcement.setContent(content);

        announcement.setCreationDate(Calendar.getInstance().getTime());

        int id = (Integer) session.save(announcement);

        return (Announcement) session.get(Announcement.class, id);
    }

    public String deleteAnnouncement(int announcementId) {
        Announcement announcement = (Announcement) session.get(Announcement.class, announcementId);
        String subject = announcement.getSubject();
        session.delete(announcement);
        return subject;
    }

    public boolean mayDelete(int tutorId, int announcementId) {
        if (((Announcement) session.get(Announcement.class, announcementId)).getCurriculumLevel() == null) {
            return false;
        }

        return session.createQuery("from Announcement a "
                + "where a.idAnnouncement = :accouncementId "
                + "and a.curriculumLevel in "
                + "(select ud2.curriculumLevel "
                + "from UserData ud2 "
                + "where ud2.id.account = :tutorId "
                + "and ud2.id.profileType = :tutorType)").setParameter("accouncementId", announcementId).setParameter("tutorId", tutorId).setParameter("tutorType", PROFILE_TYPE_TUTOR).uniqueResult() != null;
    }

    /**
     * Counts all accouncements.
     * @return quantity of all announcements
     */
    public long countAllAnnouncements() {
        return (Long) session.createQuery("select distinct count(a) from Announcement a").uniqueResult();
    }

    public int countAnnouncementsByTutor(int tutorId) {
        return countAnnouncementsByProfileType(tutorId, PROFILE_TYPE_TUTOR);
    }

    public int countAnnouncementsByStuden(int studentId) {
        return countAnnouncementsByProfileType(studentId, PROFILE_TYPE_STUDENT);
    }

    protected int countAnnouncementsByProfileType(int userId, short profileType) {
        //new Announcement().getCurriculumLevel().getId();
        // in
        // new UserData().getId().getProfileType();
        return ((Long) session.createQuery("select distinct count(a) "
                + "from Announcement a "
                + "where a.curriculumLevel.id in "
                + "(select userData.id.curriculumLevel "
                + "from UserData userData "
                + "where userData.id.account = :userId "
                + "and userData.id.profileType = :profileType)").setParameter("userId", userId).setParameter("profileType", profileType).uniqueResult()).intValue();
    }

    /**
     * Counts announcements for student or tutor.
     * @param userId
     * @return quantity of announcements
     */
    public int countAnnouncementsByUser(int userId) {
        return (Integer) session.createQuery("select distinct count(a) from Announcement a "
                + "where idCurriculumLevel in "
                + "(select ud2.curriculumLevel.id "
                + "from UserData ud2 where "
                + "ud2.id.account = :userId)").setParameter("userId", userId).uniqueResult();
    }
}
